/* Práctica 3a */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/shm.h>

double timeval_diff(struct timeval *a, struct timeval *b);

int KEY;

int main(int argc, char* argv[])
{

  int numero_hijos;
  double tiempo_requerido = 0;
  double suma = 0;
  int pid;
  struct timeval tiempo_inicio, tiempo_final;
  int i;
  int id;
  double *ctrl;
  int status;


  if(argc!=2)
  {
    perror("Error en el número de parámetros de entrada.\n");
    exit(-1);
  }

  numero_hijos = atoi(argv[1]);
  KEY = ftok(".",'z');
  id = shmget(KEY, numero_hijos*sizeof(double), IPC_CREAT|0666);
  if(id < 0)
  {
      printf("Error en el shmget\n");
      exit(-1);
  }

  ctrl = (double *)shmat(id,0,0);


  printf("Son el padre, voy a hacer %d hijos. ",numero_hijos);
  printf("Mi PID = %d \n",getpid());

  for (i=0; i<numero_hijos; i++)
  {
    gettimeofday(&tiempo_inicio,NULL);
    pid = fork();
    switch(pid)
    {
        case -1:
        /* Error */
            perror("Error al crear un hijo.\n");
            break;
        case 0:
        /* Hijo */
            printf("Soy el hijo n = %d, ", i + 1);
            printf("Mi PID = %d\n", getpid());
            gettimeofday(&tiempo_final,NULL);
            tiempo_requerido = timeval_diff(&tiempo_final, &tiempo_inicio);
            printf("Tiempo requerido para crear el hijo %d es => %g  us\n", i, tiempo_requerido);
            ctrl[i] = tiempo_requerido;
            exit(status);
            break;
        default:
        /* Proceso padre */
            waitpid(pid,&status,0);
            break;
    }
  }

    for (i = 0; i < numero_hijos; i++)
    {
        suma = suma + ctrl[i];
    }

    printf("El tiempo total es => %g us\n", suma);
    printf("El promedio es => %g us\n", suma/numero_hijos);


    shmctl(id,IPC_RMID,0);
    exit(0);
}

/* -------------------------------------------------- */
/* retorna "a - b" en segundos */
double timeval_diff(struct timeval *a, struct timeval *b)
{
  return
    (double)(a->tv_sec/1000000 + (double)a->tv_usec) -
    (double)(b->tv_sec/1000000 + (double)b->tv_usec);
}
